SPDX-FileCopyrightText: 2021 Gaston Demoulin & Loïc Mabire SPDX-FileCopyrightText: 2024 AlICe laboratory https://alicelab.be
SPDX-License-Identifier: GPL-3.0-or-later
Music in similar motion - Philip Glass 1969 # # final script- 25/01/2020 - Loïc M - Gaston D # Blender 2.93.4 #
import bpy
import random
import bmesh
import mathdef clean():  # cleanup fonction
    bpy.ops.object.select_all(action="SELECT")
    bpy.ops.object.delete(use_global=False)
    bpy.ops.outliner.orphans_purge()def curve(measure, coords):
    curveData = bpy.data.curves.new(measure, type="CURVE")
    curveData.dimensions = "3D"
    curveData.resolution_u = 20
    polyline = curveData.splines.new("NURBS")
    polyline.points.add(len(coords) - 1)
    for i, coord in enumerate(coords):
        x, y, z = coord
        polyline.points[i].co = (x, y, z, 1)
    curveOB = bpy.data.objects.new("mesure", curveData)
    curveData.extrude = 0.1
    myCollection = bpy.context.collection
    myCollection.objects.link(curveOB)
    bpy.data.scenes[0].collection.objects.link(curveOB)
    return curveOBdef cube(position, echelle):
    bpy.ops.mesh.primitive_cube_add(
        size=1, enter_editmode=False, location=position, scale=echelle
    )
    bpy.ops.context.renamedef get_objects(name):
    res = []
    for obj in bpy.data.objects:
        if name in obj.name:
            res.append(obj)
    return resdef dot():
    print("-----")
    print("-----")
clean()innit variable
listeZ = [-1, 1]  # possibilities on z
listeX = [2, 3, 4]  # possibilities on x
newco = []
sizex = 1
nbrepet = 0
nbadd = 0
list = [1, 0, 0, 0, 0, 0]
startInstrument = [0]
list_EP = []
facteur_EP = []
offsetrandom = []
ibis = -1
addX = 0
addX2 = 0strat by writing the first measure as coordinates
coord_list = [
    [0, 0, 0],
    [0, 0, 0],
    [0, 0, 0],
    [random.choice(listeX), 0, random.choice(listeX)],
]  # the first measure always start at 0,0,0
for i in range(0, 1):
    coord_list.append(
        [
            coord_list[3 + i][0] + random.choice(listeX),
            0,
            coord_list[3 + i][2] + random.choice(listeZ),
        ]
    )
for coordfin in range(0, 2):
    coord_list.append(coord_list[-1])
coord_list_bis = coord_list
coord_list_prec = coord_listchoice start instrument
nbinstrument = random.randint(3, 5)
if nbinstrument >= 4:
    var = 1.5
else:
    var = 2.5
for a in range(0, nbinstrument):
    facteur_EP.append(var * random.uniform(0.75, 1.25))
    offsetrandom.append(random.uniform(-0.2, 0.2))
print("start intrumentbis")
print(nbinstrument)
print(startInstrument)strat writing for console reading
dot()
print("start")
dot()              curve                     #
    main loop writing the 14 measure of the piece as an evolutive coord_list
for i in range(
    0, 14
):  # all the rules writing the curves are stats from the original pieceeach new coord is added randomly within the actual list at ‘index’, keeping the first and last coords the same
    index = random.randint(3, len(coord_list) - 4)  # choose one coordinate in the list
    prevx, prevy, prevz = coord_list[index]  # read the coordinate at index14% chance of adding 0 coordinate, 50% of adding one, 36% of adding 2
    resultchoice = random.randint(1, 100)  # get the % for coord choicereset variables
    addX = 0
    addX2 = 0
    choice0 = False
    choice3 = Falseconsole reading
    dot()
    print("iteration", i + 1)
    print("coord_liststart", coord_list)
    print("index choosed", index, ":", coord_list[index])
    if resultchoice <= 14:  # 14% -  add 0 coordinate
        print("add 0")
        nbadd = 0
        choice0 = True
    elif resultchoice <= 64:  # 50% -  add 1 coordinate
        print("add 1")
        nbadd = 2with the index coordinate we find the next one within the 6 possibilities:
        addX = random.choice(listeX)
        newX = prevx + addX
        newZ = prevz + random.choice(listeZ)doing it twice
        if (
            newZ < -2
            or coord_list[index - 2][2]
            > coord_list[index - 1][2]
            > coord_list[index][2]
        ):
            newZ = newZ + 1
        elif (
            newZ > 4
            or coord_list[index - 2][2]
            < coord_list[index - 1][2]
            < coord_list[index][2]
        ):
            newZ = newZ - 1
    else:  # 36% -  add 2 coordinate
        print("add 2")
        choice3 = True
        nbadd = 3with the index coordinate we find the next one within the 6 possibilities:
        addX = random.choice(listeX)
        newX = prevx + addX
        newZ = prevz + random.choice(listeZ)bounding box
        if (
            newZ < -2
            or coord_list[index - 2][2]
            > coord_list[index - 1][2]
            > coord_list[index][2]
        ):
            newZ = newZ + 1
        elif (
            newZ > 4
            or coord_list[index - 2][2]
            < coord_list[index - 1][2]
            < coord_list[index][2]
        ):
            newZ = newZ - 1doing it twice
        addX2 = random.choice(listeX)
        newX2 = newX + addX
        newZ2 = newZ + random.choice(listeZ)bounding box
        if (
            newZ < -2
            or coord_list[index - 2][2]
            > coord_list[index - 1][2]
            > coord_list[index][2]
        ):
            newZ = newZ + 1
        elif (
            newZ > 4
            or coord_list[index - 2][2]
            < coord_list[index - 1][2]
            < coord_list[index][2]
        ):
            newZ = newZ - 1one in 5 chance to delete the first note of the measure
    if 9 > len(coord_list) > 13:
        chancesuppr = [1, 2, 3, 4, 5]
        resultatsuprr = random.choice(chancesuppr)
        if resultatsuppr == 3:
            print("SUPPR", coord_list[4, 5])
            del coord_list[4, 5]
    coord_list_prec = coord_listinsert the new coordinate Xn1 after the Xn choosen
    if choice0 == False:  # newco = coordlist[index] if choice 0
        newco = [newX, 0, newZ]
        coord_list.insert(index + 1, newco)
        print("newco ", newco)
    if choice3 == True:
        newco2 = [newX2, 0, newZ2]
        coord_list.insert(index + 2, newco2)
        print("newco2", newco2)move the coordinate after the Xn choosen on X by choice 0,1 or 2
    for coord in coord_list[index + nbadd :]:
        if i == 0:
            coord[0] = coord[0] + (addX + addX2) / 3
        else:
            coord[0] = coord[0] + addX + addX2
        print(addX + addX2)
    dot()
    print("coord_list", coord_list)
    print("nombrecoo", len(coord_list))
    dot()
    print("00000")adding space
    nbcoo = len(coord_list)
    for l in range(0, nbcoo):
        xbisH, ybisH, zbisH = coord_list[l]
        del coord_list[l]
        zbisH = zbisH + 1.45  # space between repetition
        coord_list.insert(l, [xbisH, ybisH, zbisH])repetition courbe bis
    nbrepet = random.randint(3, 10)
    for k in range(0, nbrepet):
        for voixa in range(0, nbinstrument):
            if random.randint(0, 60) == 60:
                list[voixa] = 1
            if i >= 13:
                list[voixa] = 1              extrusion                  #
        for k in range(0, nbrepet):move up every repetition
        for j in range(0, nbcoo):
            xbis, ybis, zbis = coord_list[j]
            del coord_list[j]
            zbis = zbis + 0.5
            coobis = [xbis, ybis, zbis]
            coord_list_bis.insert(j, coobis)
        for voix in range(0, nbinstrument):thickness and offset variable to always have 10cm lenght
            if voix == nbinstrument - 1:
                offset = -1
            elif voix == 0:
                offset = 1
            else:
                offset = 0 + offsetrandom[voix]
            if list[voix] == 1:
                maCourbeCreeBis = curve("mesurebis", coord_list_bis)
                maCourbeCreeBis.select_set(True)  # selection
                sizex = 10 / coord_list[-1][0]  # resize for curves = 10cm
                bpy.ops.transform.resize(value=(sizex, 1, 1))
                bpy.context.view_layer.objects.active = (
                    maCourbeCreeBis  # 'maCourbeCreeBis' is the active object now
                )
                bpy.ops.object.modifier_add(type="SOLIDIFY")
                bpy.context.object.modifiers["Solidify"].thickness = facteur_EP[
                    voix
                ]  # facteur_EP #list_facteur(ii)
                bpy.context.object.modifiers["Solidify"].offset = offset
                bpy.ops.transform.translate(
                    value=(0, (10 / (nbinstrument - 1)) * voix, 0)
                )
                maCourbeCreeBis.select_set(False)
            if k == (nbrepet - 3) and voix == 0:  # signal
                maCourbeCreeBis.select_set(True)
                bpy.context.view_layer.objects.active = maCourbeCreeBis
                bpy.ops.object.modifier_add(type="SOLIDIFY")
                bpy.context.object.modifiers["Solidify"].thickness = (
                    10  # extrusion of the signal
                )
                bpy.context.object.modifiers["Solidify"].offset = 1
                maCourbeCreeBis.select_set(False)
    print(list)
    ibis += 1
    i += 1              pillars                    #
    x, y, max_ztotal = max(coord_list_bis, key=lambda item: item[2])
tailleRectx = 0.2
tailleRecty = 0.1
for cix in range(0, 4):
    if cix == 0:
        ix = 1
    elif cix == 3:
        ix = 9
    else:
        ix = (10 / 3.5) * cix + 1
    for ciy in range(1, 6):
        if ciy == 1:
            iy = 1
        elif ciy == 5:
            iy = 9
        else:
            iy = (10 / 5) * ciy - 1
        cube(
            (ix + tailleRectx / 2, iy, max_ztotal / 2),
            (tailleRectx, tailleRecty, max_ztotal),
        )Ext = maCourbeCreeBis  # la tour
hauteur_cadrage = random.uniform(
    5, (max_ztotal - 5)
)  # pos z of the extraction of the towerdef boolean(mod, object):
    bpy.ops.object.modifier_add(type="BOOLEAN")
    bpy.context.object.modifiers["Boolean"].operation = "INTERSECT"
    bpy.context.object.modifiers["Boolean"].solver = mod
    bpy.context.object.modifiers["Boolean"].object = objectjoin everything in one MESH
bpy.ops.object.select_all(action="SELECT")
bpy.context.view_layer.objects.active = maCourbeCreeBis
bpy.ops.object.convert(target="MESH")
bpy.ops.object.join()
bpy.context.active_object.name = "Ext"Cadrage 1 : first cut
cube((5, 5, hauteur_cadrage), (12, 12, 10))
cube1 = get_objects("Cube")[0]
boolean("FAST", Ext)Cadrage 2 : Cube more précise but solver = FAST
cube((5, 5, hauteur_cadrage), (10.2, 10.2, 10))
cube2 = get_objects("Cube.001")[0]
boolean("FAST", cube1)
bpy.ops.object.modifier_apply(modifier="Boolean")Cadrage 3 : solver = EXACT
cube((5, 5, hauteur_cadrage), (10.2, 10.2, 10))
boolean("EXACT", cube2)on applique la fonction boolean cette fois seulement
bpy.ops.object.modifier_apply(modifier="Boolean")replace the cube at 0;0
bpy.ops.transform.translate(value=(0, 0, -hauteur_cadrage + 5))
bpy.ops.object.select_all(action="DESELECT")cleanup
cube1.select_set(True)
bpy.ops.object.delete(use_global=False)
cube2.select_set(True)
bpy.ops.object.delete(use_global=False)
tour = get_objects("Ext")[0]
tour.select_set(True)
bpy.ops.transform.translate(value=(20, 0, 0))closing volumes
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.editmode_toggle()bpy.ops.mesh.edge_face_add()
bpy.ops.mesh.normals_make_consistent(inside=True)
bpy.ops.mesh.remove_doubles(threshold=0.001)
bpy.ops.mesh.select_all(action="DESELECT")
bpy.ops.object.editmode_toggle()